package com.ponhu.ea2.stockcenter.provider.service.biz.stockwarehouse;

import com.alibaba.nacos.common.utils.CollectionUtils;
import com.ponhu.ea2.stockcenter.dto.WMSEventInfoDTO;
import com.ponhu.ea2.stockcenter.enums.ExchangeActionTypeEnum;
import com.ponhu.ea2.stockcenter.provider.entity.StockInventoryDocOccupy;
import com.ponhu.ea2.stockcenter.provider.entity.StockInventoryReal;
import com.ponhu.ea2.stockcenter.provider.support.exception.StockRuntimeException;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static com.ponhu.ea2.stockcenter.enums.ExchangeActionTypeEnum.*;
import static com.ponhu.ea2.stockcenter.enums.ResponseCodeEnum.STOCK_SALES_EXCEPTION_900301;
import static com.ponhu.ea2.stockcenter.enums.ResponseCodeEnum.STOCK_SALES_EXCEPTION_900303;

/**
 * 采退出库、盘亏出库、销售出库、其他出库、调拨计划出库
 */
@Component
public class CommonOutHandler extends AbsCoreHandler {

    public CommonOutHandler() {
        inOccupy = false;
        operateWarehouse = false; // 当前操作仓库是 outWarehouse
        whActionTypeArr = new ExchangeActionTypeEnum[]{
                SALES_RETURN_CANCLE_OUT,
                PURCHASE_CANCEL_OUT,
                PURCHASE_RETURN_OUT,
                TRANSFER_PLAN_OUT,
                CHECK_LOSS_OUT,
                OTHER_OUT,
                SALES_OUT
        };
    }

    @Override
    protected void absHandle(WMSEventInfoDTO eventInfoDTO) {

        // 任务链路中的仓库库存变动预校验
//        preTraceCheck(eventInfoDTO);

        // 仓库出库库存校验
        commonOutStockCheck(eventInfoDTO);

        // 仓库库存变动数据库操作
        stockWarehouseHandle(eventInfoDTO);

        // 销售出库和采退出库：修改销售侧单据库存占用表为已出库
        List<ExchangeActionTypeEnum> typeEnumList = Arrays.asList(
                PURCHASE_RETURN_OUT, SALES_OUT);
        if (typeEnumList.contains(eventInfoDTO.getActionType())) {
            try {
                updateStockOccupyStatus(eventInfoDTO);
            } catch (Exception e) {
                if (eventInfoDTO.getActionType() == PURCHASE_RETURN_OUT) {
                    // 修正分批采退导致的占用数异常
                    Map<String, Integer> infoMap = inventoryLocal.get();
                    List<StockInventoryReal> inventoryReals = stockInventoryRealService.getRealInventoryStockList(inventoryLocal.get().keySet())
                            .stream().map(stock -> stock.setUsedStockNum(Math.max(stock.getUsedStockNum() - infoMap.get(stock.getInventoryCode()), 0)))
                            .collect(Collectors.toList());
                    stockInventoryRealService.updateBatchById(inventoryReals);
                } else throw e;
            }
        }

        // 仓库库存变动对销售库存影响
        salesStockHandle(eventInfoDTO);

        // 修改货品在途库存数量
        if (eventInfoDTO.getActionType() == TRANSFER_PLAN_OUT)
            updateFreeStockNum(eventInfoDTO);
    }

    /**
     * 修改销售侧单据库存占用表为已出库
     */
    protected void updateStockOccupyStatus(WMSEventInfoDTO eventInfoDTO) {

        // 销售出库或采退出库 出可售仓
        if (ObjectUtils.isNotEmpty(saleEventLocal.get())) {
            // 更新销售侧单据库存占用表状态为已出库未占用
            if (!stockInventoryDocOccupyService.takeDocRecordOutOfWarehouseForUsed(
                    eventInfoDTO.getDocNo(), eventInfoDTO.getActionType(), saleEventLocal.get())) {
                throw new StockRuntimeException(STOCK_SALES_EXCEPTION_900301);
            }
        }

        // 销售出库或采退出库 出不可售仓
        if (ObjectUtils.isEmpty(saleEventLocal.get())) {
            // 获取已下单未占用已调拨申请且已出可售仓的货品占用记录集合
            List<StockInventoryDocOccupy> occupyList = stockInventoryDocOccupyService
                    .getPlacedAndNoOccupyAndTransferAppliedAndOutedDocRecord(eventInfoDTO.getDocNo());
            // 销售出库或采退出库出不可售仓，则销售侧单据库存占用必须已经提前释放了
            if (CollectionUtils.isEmpty(occupyList)) {
                throw new StockRuntimeException(STOCK_SALES_EXCEPTION_900303);
            }

            // 更新销售侧单据库存占用表状态为已出库
            if (!stockInventoryDocOccupyService.takeDocRecordOutOfWarehouseForNoUsed(
                    eventInfoDTO.getDocNo(), eventInfoDTO.getActionType(), saleEventLocal.get())) {
                throw new StockRuntimeException(STOCK_SALES_EXCEPTION_900301);
            }
        }
    }

}
